home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Date.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  37.5 KB  |  1,253 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. //
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2005 Baba Buehler, Pierre-Alain Joye              |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to the New BSD license, That is bundled  |
  8. // | with this package in the file LICENSE, and is available through      |
  9. // | the world-wide-web at                                                |
  10. // | http://www.opensource.org/licenses/bsd-license.php                   |
  11. // | If you did not receive a copy of the new BSDlicense and are unable   |
  12. // | to obtain it through the world-wide-web, please send a note to       |
  13. // | pear-dev@lists.php.net so we can mail you a copy immediately.        |
  14. // +----------------------------------------------------------------------+
  15. // | Author: Baba Buehler <baba@babaz.com>                                |
  16. // |         Pierre-Alain Joye <pajoye@php.net>                           |
  17. // +----------------------------------------------------------------------+
  18.  
  19. /**
  20.  * Generic date handling class for PEAR
  21.  *
  22.  * Generic date handling class for PEAR.  Attempts to be time zone aware
  23.  * through the Date::TimeZone class.  Supports several operations from
  24.  * Date::Calc on Date objects.
  25.  *
  26.  * @category   Date and Time
  27.  * @package    Date
  28.  * @author     Baba Buehler <baba@babaz.com>
  29.  * @author     Pierre-Alain Joye <pajoye@php.net>
  30.  * @copyright  1997-2005 The PHP Group
  31.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  32.  * @version    CVS: $Id: Date.php,v 1.35 2005/11/15 00:16:38 pajoye Exp $
  33.  * @link       http://pear.php.net/package/Date
  34.  */
  35.  
  36. /**@#+
  37.  * Include supporting classes
  38.  */
  39. require_once 'Date/TimeZone.php';
  40. require_once 'Date/Calc.php';
  41. require_once 'Date/Span.php';
  42. /**@#-*/
  43.  
  44. /**@#+
  45.  * Output formats.  Pass this to getDate().
  46.  */
  47. /**
  48.  * "YYYY-MM-DD HH:MM:SS"
  49.  */
  50. define('DATE_FORMAT_ISO', 1);
  51. /**
  52.  * "YYYYMMSSTHHMMSS(Z|(+/-)HHMM)?"
  53.  */
  54. define('DATE_FORMAT_ISO_BASIC', 2);
  55. /**
  56.  * "YYYY-MM-SSTHH:MM:SS(Z|(+/-)HH:MM)?"
  57.  */
  58. define('DATE_FORMAT_ISO_EXTENDED', 3);
  59. /**
  60.  * "YYYY-MM-SSTHH:MM:SS(.S*)?(Z|(+/-)HH:MM)?"
  61.  */
  62. define('DATE_FORMAT_ISO_EXTENDED_MICROTIME', 6);
  63. /**
  64.  * "YYYYMMDDHHMMSS"
  65.  */
  66. define('DATE_FORMAT_TIMESTAMP', 4);
  67. /**
  68.  * long int, seconds since the unix epoch
  69.  */
  70. define('DATE_FORMAT_UNIXTIME', 5);
  71. /**@#-*/
  72.  
  73. /**
  74.  * Generic date handling class for PEAR
  75.  *
  76.  * Generic date handling class for PEAR.  Attempts to be time zone aware
  77.  * through the Date::TimeZone class.  Supports several operations from
  78.  * Date::Calc on Date objects.
  79.  *
  80.  * @author     Baba Buehler <baba@babaz.com>
  81.  * @author     Pierre-Alain Joye <pajoye@php.net>
  82.  * @copyright  1997-2005 The PHP Group
  83.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  84.  * @version    Release: 1.4.6
  85.  * @link       http://pear.php.net/package/Date
  86.  */
  87. class Date
  88. {
  89.     /**
  90.      * the year
  91.      * @var int
  92.      */
  93.     var $year;
  94.     /**
  95.      * the month
  96.      * @var int
  97.      */
  98.     var $month;
  99.     /**
  100.      * the day
  101.      * @var int
  102.      */
  103.     var $day;
  104.     /**
  105.      * the hour
  106.      * @var int
  107.      */
  108.     var $hour;
  109.     /**
  110.      * the minute
  111.      * @var int
  112.      */
  113.     var $minute;
  114.     /**
  115.      * the second
  116.      * @var int
  117.      */
  118.     var $second;
  119.     /**
  120.      * the parts of a second
  121.      * @var float
  122.      */
  123.     var $partsecond;
  124.  
  125.     /**
  126.      * timezone for this date
  127.      * @var object Date_TimeZone
  128.      */
  129.     var $tz;
  130.  
  131.     /**
  132.      * define the default weekday abbreviation length
  133.      * used by ::format()
  134.      * @var int
  135.      */
  136.     var $getWeekdayAbbrnameLength = 3;
  137.  
  138.  
  139.     /**
  140.      * Constructor
  141.      *
  142.      * Creates a new Date Object initialized to the current date/time in the
  143.      * system-default timezone by default.  A date optionally
  144.      * passed in may be in the ISO 8601, TIMESTAMP or UNIXTIME format,
  145.      * or another Date object.  If no date is passed, the current date/time
  146.      * is used.
  147.      *
  148.      * @access public
  149.      * @see setDate()
  150.      * @param mixed $date optional - date/time to initialize
  151.      * @return object Date the new Date object
  152.      */
  153.     function Date($date = null)
  154.     {
  155.         $this->tz = Date_TimeZone::getDefault();
  156.         if (is_null($date)) {
  157.             $this->setDate(date("Y-m-d H:i:s"));
  158.         } elseif (is_a($date, 'Date')) {
  159.             $this->copy($date);
  160.         } else {
  161.             $this->setDate($date);
  162.         }
  163.     }
  164.  
  165.     /**
  166.      * Set the fields of a Date object based on the input date and format
  167.      *
  168.      * Set the fields of a Date object based on the input date and format,
  169.      * which is specified by the DATE_FORMAT_* constants.
  170.      *
  171.      * @access public
  172.      * @param string $date input date
  173.      * @param int $format Optional format constant (DATE_FORMAT_*) of the input date.
  174.      *                    This parameter isn't really needed anymore, but you could
  175.      *                    use it to force DATE_FORMAT_UNIXTIME.
  176.      */
  177.     function setDate($date, $format = DATE_FORMAT_ISO)
  178.     {
  179.  
  180.         if (
  181.             preg_match('/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?$/i', $date, $regs)
  182.             && $format != DATE_FORMAT_UNIXTIME) {
  183.             // DATE_FORMAT_ISO, ISO_BASIC, ISO_EXTENDED, and TIMESTAMP
  184.             // These formats are extremely close to each other.  This regex
  185.             // is very loose and accepts almost any butchered format you could
  186.             // throw at it.  e.g. 2003-10-07 19:45:15 and 2003-10071945:15
  187.             // are the same thing in the eyes of this regex, even though the
  188.             // latter is not a valid ISO 8601 date.
  189.             $this->year       = $regs[1];
  190.             $this->month      = $regs[2];
  191.             $this->day        = $regs[3];
  192.             $this->hour       = isset($regs[5])?$regs[5]:0;
  193.             $this->minute     = isset($regs[6])?$regs[6]:0;
  194.             $this->second     = isset($regs[7])?$regs[7]:0;
  195.             $this->partsecond = isset($regs[8])?(float)$regs[8]:(float)0;
  196.  
  197.             // if an offset is defined, convert time to UTC
  198.             // Date currently can't set a timezone only by offset,
  199.             // so it has to store it as UTC
  200.             if (isset($regs[9])) {
  201.                 $this->toUTCbyOffset($regs[9]);
  202.             }
  203.         } elseif (is_numeric($date)) {
  204.             // UNIXTIME
  205.             $this->setDate(date("Y-m-d H:i:s", $date));
  206.         } else {
  207.             // unknown format
  208.             $this->year       = 0;
  209.             $this->month      = 1;
  210.             $this->day        = 1;
  211.             $this->hour       = 0;
  212.             $this->minute     = 0;
  213.             $this->second     = 0;
  214.             $this->partsecond = (float)0;
  215.         }
  216.     }
  217.  
  218.     /**
  219.      * Get a string (or other) representation of this date
  220.      *
  221.      * Get a string (or other) representation of this date in the
  222.      * format specified by the DATE_FORMAT_* constants.
  223.      *
  224.      * @access public
  225.      * @param int $format format constant (DATE_FORMAT_*) of the output date
  226.      * @return string the date in the requested format
  227.      */
  228.     function getDate($format = DATE_FORMAT_ISO)
  229.     {
  230.         switch ($format) {
  231.         case DATE_FORMAT_ISO:
  232.             return $this->format("%Y-%m-%d %T");
  233.             break;
  234.         case DATE_FORMAT_ISO_BASIC:
  235.             $format = "%Y%m%dT%H%M%S";
  236.             if ($this->tz->getID() == 'UTC') {
  237.                 $format .= "Z";
  238.             }
  239.             return $this->format($format);
  240.             break;
  241.         case DATE_FORMAT_ISO_EXTENDED:
  242.             $format = "%Y-%m-%dT%H:%M:%S";
  243.             if ($this->tz->getID() == 'UTC') {
  244.                 $format .= "Z";
  245.             }
  246.             return $this->format($format);
  247.             break;
  248.         case DATE_FORMAT_ISO_EXTENDED_MICROTIME:
  249.             $format = "%Y-%m-%dT%H:%M:%s";
  250.             if ($this->tz->getID() == 'UTC') {
  251.                 $format .= "Z";
  252.             }
  253.             return $this->format($format);
  254.             break;
  255.         case DATE_FORMAT_TIMESTAMP:
  256.             return $this->format("%Y%m%d%H%M%S");
  257.             break;
  258.         case DATE_FORMAT_UNIXTIME:
  259.             return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
  260.             break;
  261.         }
  262.     }
  263.  
  264.     /**
  265.      * Copy values from another Date object
  266.      *
  267.      * Makes this Date a copy of another Date object.
  268.      *
  269.      * @access public
  270.      * @param object Date $date Date to copy from
  271.      */
  272.     function copy($date)
  273.     {
  274.         $this->year = $date->year;
  275.         $this->month = $date->month;
  276.         $this->day = $date->day;
  277.         $this->hour = $date->hour;
  278.         $this->minute = $date->minute;
  279.         $this->second = $date->second;
  280.         $this->tz = $date->tz;
  281.     }
  282.  
  283.     /**
  284.      *  Date pretty printing, similar to strftime()
  285.      *
  286.      *  Formats the date in the given format, much like
  287.      *  strftime().  Most strftime() options are supported.<br><br>
  288.      *
  289.      *  formatting options:<br><br>
  290.      *
  291.      *  <code>%a  </code>  abbreviated weekday name (Sun, Mon, Tue) <br>
  292.      *  <code>%A  </code>  full weekday name (Sunday, Monday, Tuesday) <br>
  293.      *  <code>%b  </code>  abbreviated month name (Jan, Feb, Mar) <br>
  294.      *  <code>%B  </code>  full month name (January, February, March) <br>
  295.      *  <code>%C  </code>  century number (the year divided by 100 and truncated to an integer, range 00 to 99) <br>
  296.      *  <code>%d  </code>  day of month (range 00 to 31) <br>
  297.      *  <code>%D  </code>  same as "%m/%d/%y" <br>
  298.      *  <code>%e  </code>  day of month, single digit (range 0 to 31) <br>
  299.      *  <code>%E  </code>  number of days since unspecified epoch (integer, Date_Calc::dateToDays()) <br>
  300.      *  <code>%H  </code>  hour as decimal number (00 to 23) <br>
  301.      *  <code>%I  </code>  hour as decimal number on 12-hour clock (01 to 12) <br>
  302.      *  <code>%j  </code>  day of year (range 001 to 366) <br>
  303.      *  <code>%m  </code>  month as decimal number (range 01 to 12) <br>
  304.      *  <code>%M  </code>  minute as a decimal number (00 to 59) <br>
  305.      *  <code>%n  </code>  newline character (\n) <br>
  306.      *  <code>%O  </code>  dst-corrected timezone offset expressed as "+/-HH:MM" <br>
  307.      *  <code>%o  </code>  raw timezone offset expressed as "+/-HH:MM" <br>
  308.      *  <code>%p  </code>  either 'am' or 'pm' depending on the time <br>
  309.      *  <code>%P  </code>  either 'AM' or 'PM' depending on the time <br>
  310.      *  <code>%r  </code>  time in am/pm notation, same as "%I:%M:%S %p" <br>
  311.      *  <code>%R  </code>  time in 24-hour notation, same as "%H:%M" <br>
  312.      *  <code>%s  </code>  seconds including the decimal representation smaller than one second <br>
  313.      *  <code>%S  </code>  seconds as a decimal number (00 to 59) <br>
  314.      *  <code>%t  </code>  tab character (\t) <br>
  315.      *  <code>%T  </code>  current time, same as "%H:%M:%S" <br>
  316.      *  <code>%w  </code>  weekday as decimal (0 = Sunday) <br>
  317.      *  <code>%U  </code>  week number of current year, first sunday as first week <br>
  318.      *  <code>%y  </code>  year as decimal (range 00 to 99) <br>
  319.      *  <code>%Y  </code>  year as decimal including century (range 0000 to 9999) <br>
  320.      *  <code>%%  </code>  literal '%' <br>
  321.      * <br>
  322.      *
  323.      * @access public
  324.      * @param string format the format string for returned date/time
  325.      * @return string date/time in given format
  326.      */
  327.     function format($format)
  328.     {
  329.         $output = "";
  330.  
  331.         for($strpos = 0; $strpos < strlen($format); $strpos++) {
  332.             $char = substr($format,$strpos,1);
  333.             if ($char == "%") {
  334.                 $nextchar = substr($format,$strpos + 1,1);
  335.                 switch ($nextchar) {
  336.                 case "a":
  337.                     $output .= Date_Calc::getWeekdayAbbrname($this->day,$this->month,$this->year, $this->getWeekdayAbbrnameLength);
  338.                     break;
  339.                 case "A":
  340.                     $output .= Date_Calc::getWeekdayFullname($this->day,$this->month,$this->year);
  341.                     break;
  342.                 case "b":
  343.                     $output .= Date_Calc::getMonthAbbrname($this->month);
  344.                     break;
  345.                 case "B":
  346.                     $output .= Date_Calc::getMonthFullname($this->month);
  347.                     break;
  348.                 case "C":
  349.                     $output .= sprintf("%02d",intval($this->year/100));
  350.                     break;
  351.                 case "d":
  352.                     $output .= sprintf("%02d",$this->day);
  353.                     break;
  354.                 case "D":
  355.                     $output .= sprintf("%02d/%02d/%02d",$this->month,$this->day,$this->year);
  356.                     break;
  357.                 case "e":
  358.                     $output .= $this->day * 1; // get rid of leading zero
  359.                     break;
  360.                 case "E":
  361.                     $output .= Date_Calc::dateToDays($this->day,$this->month,$this->year);
  362.                     break;
  363.                 case "H":
  364.                     $output .= sprintf("%02d", $this->hour);
  365.                     break;
  366.                 case 'h':
  367.                     $output .= sprintf("%d", $this->hour);
  368.                     break;
  369.                 case "I":
  370.                     $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
  371.                     $output .= sprintf("%02d", $hour==0 ? 12 : $hour);
  372.                     break;
  373.                 case "i":
  374.                     $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
  375.                     $output .= sprintf("%d", $hour==0 ? 12 : $hour);
  376.                     break;
  377.                 case "j":
  378.                     $output .= Date_Calc::julianDate($this->day,$this->month,$this->year);
  379.                     break;
  380.                 case "m":
  381.                     $output .= sprintf("%02d",$this->month);
  382.                     break;
  383.                 case "M":
  384.                     $output .= sprintf("%02d",$this->minute);
  385.                     break;
  386.                 case "n":
  387.                     $output .= "\n";
  388.                     break;
  389.                 case "O":
  390.                     $offms = $this->tz->getOffset($this);
  391.                     $direction = $offms >= 0 ? "+" : "-";
  392.                     $offmins = abs($offms) / 1000 / 60;
  393.                     $hours = $offmins / 60;
  394.                     $minutes = $offmins % 60;
  395.                     $output .= sprintf("%s%02d:%02d", $direction, $hours, $minutes);
  396.                     break;
  397.                 case "o":
  398.                     $offms = $this->tz->getRawOffset($this);
  399.                     $direction = $offms >= 0 ? "+" : "-";
  400.                     $offmins = abs($offms) / 1000 / 60;
  401.                     $hours = $offmins / 60;
  402.                     $minutes = $offmins % 60;
  403.                     $output .= sprintf("%s%02d:%02d", $direction, $hours, $minutes);
  404.                     break;
  405.                 case "p":
  406.                     $output .= $this->hour >= 12 ? "pm" : "am";
  407.                     break;
  408.                 case "P":
  409.                     $output .= $this->hour >= 12 ? "PM" : "AM";
  410.                     break;
  411.                 case "r":
  412.                     $hour = ($this->hour + 1) > 12 ? $this->hour - 12 : $this->hour;
  413.                     $output .= sprintf("%02d:%02d:%02d %s", $hour==0 ?  12 : $hour, $this->minute, $this->second, $this->hour >= 12 ? "PM" : "AM");
  414.                     break;
  415.                 case "R":
  416.                     $output .= sprintf("%02d:%02d", $this->hour, $this->minute);
  417.                     break;
  418.                 case "s":
  419.                     $output .= str_replace(',', '.', sprintf("%09f", (float)((float)$this->second + $this->partsecond)));
  420.                     break;
  421.                 case "S":
  422.                     $output .= sprintf("%02d", $this->second);
  423.                     break;
  424.                 case "t":
  425.                     $output .= "\t";
  426.                     break;
  427.                 case "T":
  428.                     $output .= sprintf("%02d:%02d:%02d", $this->hour, $this->minute, $this->second);
  429.                     break;
  430.                 case "w":
  431.                     $output .= Date_Calc::dayOfWeek($this->day,$this->month,$this->year);
  432.                     break;
  433.                 case "U":
  434.                     $output .= Date_Calc::weekOfYear($this->day,$this->month,$this->year);
  435.                     break;
  436.                 case "y":
  437.                     $output .= substr($this->year,2,2);
  438.                     break;
  439.                 case "Y":
  440.                     $output .= $this->year;
  441.                     break;
  442.                 case "Z":
  443.                     $output .= $this->tz->inDaylightTime($this) ? $this->tz->getDSTShortName() : $this->tz->getShortName();
  444.                     break;
  445.                 case "%":
  446.                     $output .= "%";
  447.                     break;
  448.                 default:
  449.                     $output .= $char.$nextchar;
  450.                 }
  451.                 $strpos++;
  452.             } else {
  453.                 $output .= $char;
  454.             }
  455.         }
  456.         return $output;
  457.  
  458.     }
  459.  
  460.     /**
  461.      * Get this date/time in Unix time() format
  462.      *
  463.      * Get a representation of this date in Unix time() format.  This may only be
  464.      * valid for dates from 1970 to ~2038.
  465.      *
  466.      * @access public
  467.      * @return int number of seconds since the unix epoch
  468.      */
  469.     function getTime()
  470.     {
  471.         return $this->getDate(DATE_FORMAT_UNIXTIME);
  472.     }
  473.  
  474.     /**
  475.      * Sets the time zone of this Date
  476.      *
  477.      * Sets the time zone of this date with the given
  478.      * Date_TimeZone object.  Does not alter the date/time,
  479.      * only assigns a new time zone.  For conversion, use
  480.      * convertTZ().
  481.      *
  482.      * @access public
  483.      * @param object Date_TimeZone $tz the Date_TimeZone object to use, if called
  484.      * with a paramater that is not a Date_TimeZone object, will fall through to
  485.      * setTZbyID().
  486.      */
  487.     function setTZ($tz)
  488.     {
  489.         if(is_a($tz, 'Date_Timezone')) {
  490.             $this->tz = $tz;
  491.         } else {
  492.             $this->setTZbyID($tz);
  493.         }
  494.     }
  495.  
  496.     /**
  497.      * Sets the time zone of this date with the given time zone id
  498.      *
  499.      * Sets the time zone of this date with the given
  500.      * time zone id, or to the system default if the
  501.      * given id is invalid. Does not alter the date/time,
  502.      * only assigns a new time zone.  For conversion, use
  503.      * convertTZ().
  504.      *
  505.      * @access public
  506.      * @param string id a time zone id
  507.      */
  508.     function setTZbyID($id)
  509.     {
  510.         if (Date_TimeZone::isValidID($id)) {
  511.             $this->tz = new Date_TimeZone($id);
  512.         } else {
  513.             $this->tz = Date_TimeZone::getDefault();
  514.         }
  515.     }
  516.  
  517.     /**
  518.      * Tests if this date/time is in DST
  519.      *
  520.      * Returns true if daylight savings time is in effect for
  521.      * this date in this date's time zone.  See Date_TimeZone::inDaylightTime()
  522.      * for compatability information.
  523.      *
  524.      * @access public
  525.      * @return boolean true if DST is in effect for this date
  526.      */
  527.     function inDaylightTime()
  528.     {
  529.         return $this->tz->inDaylightTime($this);
  530.     }
  531.  
  532.     /**
  533.      * Converts this date to UTC and sets this date's timezone to UTC
  534.      *
  535.      * Converts this date to UTC and sets this date's timezone to UTC
  536.      *
  537.      * @access public
  538.      */
  539.     function toUTC()
  540.     {
  541.         if ($this->tz->getOffset($this) > 0) {
  542.             $this->subtractSeconds(intval($this->tz->getOffset($this) / 1000));
  543.         } else {
  544.             $this->addSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
  545.         }
  546.         $this->tz = new Date_TimeZone('UTC');
  547.     }
  548.  
  549.     /**
  550.      * Converts this date to a new time zone
  551.      *
  552.      * Converts this date to a new time zone.
  553.      * WARNING: This may not work correctly if your system does not allow
  554.      * putenv() or if localtime() does not work in your environment.  See
  555.      * Date::TimeZone::inDaylightTime() for more information.
  556.      *
  557.      * @access public
  558.      * @param object Date_TimeZone $tz the Date::TimeZone object for the conversion time zone
  559.      */
  560.     function convertTZ($tz)
  561.     {
  562.         // convert to UTC
  563.         if ($this->tz->getOffset($this) > 0) {
  564.             $this->subtractSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
  565.         } else {
  566.             $this->addSeconds(intval(abs($this->tz->getOffset($this)) / 1000));
  567.         }
  568.         // convert UTC to new timezone
  569.         if ($tz->getOffset($this) > 0) {
  570.             $this->addSeconds(intval(abs($tz->getOffset($this)) / 1000));
  571.         } else {
  572.             $this->subtractSeconds(intval(abs($tz->getOffset($this)) / 1000));
  573.         }
  574.         $this->tz = $tz;
  575.     }
  576.  
  577.     /**
  578.      * Converts this date to a new time zone, given a valid time zone ID
  579.      *
  580.      * Converts this date to a new time zone, given a valid time zone ID
  581.      * WARNING: This may not work correctly if your system does not allow
  582.      * putenv() or if localtime() does not work in your environment.  See
  583.      * Date::TimeZone::inDaylightTime() for more information.
  584.      *
  585.      * @access public
  586.      * @param string id a time zone id
  587.      */
  588.     function convertTZbyID($id)
  589.     {
  590.        if (Date_TimeZone::isValidID($id)) {
  591.           $tz = new Date_TimeZone($id);
  592.        } else {
  593.           $tz = Date_TimeZone::getDefault();
  594.        }
  595.        $this->convertTZ($tz);
  596.     }
  597.  
  598.     function toUTCbyOffset($offset)
  599.     {
  600.         if ($offset == "Z" || $offset == "+00:00" || $offset == "+0000") {
  601.             $this->toUTC();
  602.             return true;
  603.         }
  604.  
  605.         if (preg_match('/([\+\-])(\d{2}):?(\d{2})/', $offset, $regs)) {
  606.             // convert offset to seconds
  607.             $hours  = (int) isset($regs[2])?$regs[2]:0;
  608.             $mins   = (int) isset($regs[3])?$regs[3]:0;
  609.             $offset = ($hours * 3600) + ($mins * 60);
  610.  
  611.             if (isset($regs[1]) && $regs[1] == "-") {
  612.                 $offset *= -1;
  613.             }
  614.  
  615.             if ($offset > 0) {
  616.                 $this->subtractSeconds(intval($offset));
  617.             } else {
  618.                 $this->addSeconds(intval(abs($offset)));
  619.             }
  620.  
  621.             $this->tz = new Date_TimeZone('UTC');
  622.             return true;
  623.         }
  624.  
  625.         return false;
  626.     }
  627.  
  628.     /**
  629.      * Adds a given number of seconds to the date
  630.      *
  631.      * Adds a given number of seconds to the date
  632.      *
  633.      * @access public
  634.      * @param int $sec the number of seconds to add
  635.      */
  636.     function addSeconds($sec)
  637.     {
  638.         $this->addSpan(new Date_Span((integer)$sec));
  639.     }
  640.  
  641.     /**
  642.      * Adds a time span to the date
  643.      *
  644.      * Adds a time span to the date
  645.      *
  646.      * @access public
  647.      * @param object Date_Span $span the time span to add
  648.      */
  649.     function addSpan($span)
  650.     {
  651.         if (!is_a($span, 'Date_Span')) {
  652.             return;
  653.         }
  654.  
  655.         $this->second += $span->second;
  656.         if ($this->second >= 60) {
  657.             $this->minute++;
  658.             $this->second -= 60;
  659.         }
  660.  
  661.         $this->minute += $span->minute;
  662.         if ($this->minute >= 60) {
  663.             $this->hour++;
  664.             if ($this->hour >= 24) {
  665.                 list($this->year, $this->month, $this->day) =
  666.                     sscanf(Date_Calc::nextDay($this->day, $this->month, $this->year), "%04s%02s%02s");
  667.                 $this->hour -= 24;
  668.             }
  669.             $this->minute -= 60;
  670.         }
  671.  
  672.         $this->hour += $span->hour;
  673.         if ($this->hour >= 24) {
  674.             list($this->year, $this->month, $this->day) =
  675.                 sscanf(Date_Calc::nextDay($this->day, $this->month, $this->year), "%04s%02s%02s");
  676.             $this->hour -= 24;
  677.         }
  678.  
  679.         $d = Date_Calc::dateToDays($this->day, $this->month, $this->year);
  680.         $d += $span->day;
  681.  
  682.         list($this->year, $this->month, $this->day) =
  683.             sscanf(Date_Calc::daysToDate($d), "%04s%02s%02s");
  684.         $this->year  = intval($this->year);
  685.         $this->month = intval($this->month);
  686.         $this->day   = intval($this->day);
  687.     }
  688.  
  689.     /**
  690.      * Subtracts a given number of seconds from the date
  691.      *
  692.      * Subtracts a given number of seconds from the date
  693.      *
  694.      * @access public
  695.      * @param int $sec the number of seconds to subtract
  696.      */
  697.     function subtractSeconds($sec)
  698.     {
  699.         $this->subtractSpan(new Date_Span($sec));
  700.     }
  701.  
  702.     /**
  703.      * Subtracts a time span to the date
  704.      *
  705.      * Subtracts a time span to the date
  706.      *
  707.      * @access public
  708.      * @param object Date_Span $span the time span to subtract
  709.      */
  710.     function subtractSpan($span)
  711.     {
  712.         if (!is_a($span, 'Date_Span')) {
  713.             return;
  714.         }
  715.         if ($span->isEmpty()) {
  716.             return;
  717.         }
  718.  
  719.         $this->second -= $span->second;
  720.         if ($this->second < 0) {
  721.             $this->minute--;
  722.             $this->second += 60;
  723.         }
  724.  
  725.         $this->minute -= $span->minute;
  726.         if ($this->minute < 0) {
  727.             $this->hour--;
  728.             if ($this->hour < 0) {
  729.                 list($this->year, $this->month, $this->day) =
  730.                     sscanf(Date_Calc::prevDay($this->day, $this->month, $this->year), "%04s%02s%02s");
  731.                 $this->hour += 24;
  732.             }
  733.             $this->minute += 60;
  734.         }
  735.  
  736.         $this->hour -= $span->hour;
  737.         if ($this->hour < 0) {
  738.             list($this->year, $this->month, $this->day) =
  739.                 sscanf(Date_Calc::prevDay($this->day, $this->month, $this->year), "%04s%02s%02s");
  740.             $this->hour += 24;
  741.         }
  742.  
  743.         $d = Date_Calc::dateToDays($this->day, $this->month, $this->year);
  744.         $d -= $span->day;
  745.  
  746.         list($this->year, $this->month, $this->day) =
  747.             sscanf(Date_Calc::daysToDate($d), "%04s%02s%02s");
  748.         $this->year  = intval($this->year);
  749.         $this->month = intval($this->month);
  750.         $this->day   = intval($this->day);
  751.     }
  752.  
  753.     /**
  754.      * Compares two dates
  755.      *
  756.      * Compares two dates.  Suitable for use
  757.      * in sorting functions.
  758.      *
  759.      * @access public
  760.      * @param object Date $d1 the first date
  761.      * @param object Date $d2 the second date
  762.      * @return int 0 if the dates are equal, -1 if d1 is before d2, 1 if d1 is after d2
  763.      */
  764.     function compare($d1, $d2)
  765.     {
  766.         $d1->convertTZ(new Date_TimeZone('UTC'));
  767.         $d2->convertTZ(new Date_TimeZone('UTC'));
  768.         $days1 = Date_Calc::dateToDays($d1->day, $d1->month, $d1->year);
  769.         $days2 = Date_Calc::dateToDays($d2->day, $d2->month, $d2->year);
  770.         if ($days1 < $days2) return -1;
  771.         if ($days1 > $days2) return 1;
  772.         if ($d1->hour < $d2->hour) return -1;
  773.         if ($d1->hour > $d2->hour) return 1;
  774.         if ($d1->minute < $d2->minute) return -1;
  775.         if ($d1->minute > $d2->minute) return 1;
  776.         if ($d1->second < $d2->second) return -1;
  777.         if ($d1->second > $d2->second) return 1;
  778.         return 0;
  779.     }
  780.  
  781.     /**
  782.      * Test if this date/time is before a certain date/time
  783.      *
  784.      * Test if this date/time is before a certain date/time
  785.      *
  786.      * @access public
  787.      * @param object Date $when the date to test against
  788.      * @return boolean true if this date is before $when
  789.      */
  790.     function before($when)
  791.     {
  792.         if (Date::compare($this,$when) == -1) {
  793.             return true;
  794.         } else {
  795.             return false;
  796.         }
  797.     }
  798.  
  799.     /**
  800.      * Test if this date/time is after a certian date/time
  801.      *
  802.      * Test if this date/time is after a certian date/time
  803.      *
  804.      * @access public
  805.      * @param object Date $when the date to test against
  806.      * @return boolean true if this date is after $when
  807.      */
  808.     function after($when)
  809.     {
  810.         if (Date::compare($this,$when) == 1) {
  811.             return true;
  812.         } else {
  813.             return false;
  814.         }
  815.     }
  816.  
  817.     /**
  818.      * Test if this date/time is exactly equal to a certian date/time
  819.      *
  820.      * Test if this date/time is exactly equal to a certian date/time
  821.      *
  822.      * @access public
  823.      * @param object Date $when the date to test against
  824.      * @return boolean true if this date is exactly equal to $when
  825.      */
  826.     function equals($when)
  827.     {
  828.         if (Date::compare($this,$when) == 0) {
  829.             return true;
  830.         } else {
  831.             return false;
  832.         }
  833.     }
  834.  
  835.     /**
  836.      * Determine if this date is in the future
  837.      *
  838.      * Determine if this date is in the future
  839.      *
  840.      * @access public
  841.      * @return boolean true if this date is in the future
  842.      */
  843.     function isFuture()
  844.     {
  845.         $now = new Date();
  846.         if ($this->after($now)) {
  847.             return true;
  848.         } else {
  849.             return false;
  850.         }
  851.     }
  852.  
  853.     /**
  854.      * Determine if this date is in the past
  855.      *
  856.      * Determine if this date is in the past
  857.      *
  858.      * @access public
  859.      * @return boolean true if this date is in the past
  860.      */
  861.     function isPast()
  862.     {
  863.         $now = new Date();
  864.         if ($this->before($now)) {
  865.             return true;
  866.         } else {
  867.             return false;
  868.         }
  869.     }
  870.  
  871.     /**
  872.      * Determine if the year in this date is a leap year
  873.      *
  874.      * Determine if the year in this date is a leap year
  875.      *
  876.      * @access public
  877.      * @return boolean true if this year is a leap year
  878.      */
  879.     function isLeapYear()
  880.     {
  881.         return Date_Calc::isLeapYear($this->year);
  882.     }
  883.  
  884.     /**
  885.      * Get the Julian date for this date
  886.      *
  887.      * Get the Julian date for this date
  888.      *
  889.      * @access public
  890.      * @return int the Julian date
  891.      */
  892.     function getJulianDate()
  893.     {
  894.         return Date_Calc::julianDate($this->day, $this->month, $this->year);
  895.     }
  896.  
  897.     /**
  898.      * Gets the day of the week for this date
  899.      *
  900.      * Gets the day of the week for this date (0=Sunday)
  901.      *
  902.      * @access public
  903.      * @return int the day of the week (0=Sunday)
  904.      */
  905.     function getDayOfWeek()
  906.     {
  907.         return Date_Calc::dayOfWeek($this->day, $this->month, $this->year);
  908.     }
  909.  
  910.     /**
  911.      * Gets the week of the year for this date
  912.      *
  913.      * Gets the week of the year for this date
  914.      *
  915.      * @access public
  916.      * @return int the week of the year
  917.      */
  918.     function getWeekOfYear()
  919.     {
  920.         return Date_Calc::weekOfYear($this->day, $this->month, $this->year);
  921.     }
  922.  
  923.     /**
  924.      * Gets the quarter of the year for this date
  925.      *
  926.      * Gets the quarter of the year for this date
  927.      *
  928.      * @access public
  929.      * @return int the quarter of the year (1-4)
  930.      */
  931.     function getQuarterOfYear()
  932.     {
  933.         return Date_Calc::quarterOfYear($this->day, $this->month, $this->year);
  934.     }
  935.  
  936.     /**
  937.      * Gets number of days in the month for this date
  938.      *
  939.      * Gets number of days in the month for this date
  940.      *
  941.      * @access public
  942.      * @return int number of days in this month
  943.      */
  944.     function getDaysInMonth()
  945.     {
  946.         return Date_Calc::daysInMonth($this->month, $this->year);
  947.     }
  948.  
  949.     /**
  950.      * Gets the number of weeks in the month for this date
  951.      *
  952.      * Gets the number of weeks in the month for this date
  953.      *
  954.      * @access public
  955.      * @return int number of weeks in this month
  956.      */
  957.     function getWeeksInMonth()
  958.     {
  959.         return Date_Calc::weeksInMonth($this->month, $this->year);
  960.     }
  961.  
  962.     /**
  963.      * Gets the full name or abbriviated name of this weekday
  964.      *
  965.      * Gets the full name or abbriviated name of this weekday
  966.      *
  967.      * @access public
  968.      * @param boolean $abbr abbrivate the name
  969.      * @return string name of this day
  970.      */
  971.     function getDayName($abbr = false, $length = 3)
  972.     {
  973.         if ($abbr) {
  974.             return Date_Calc::getWeekdayAbbrname($this->day, $this->month, $this->year, $length);
  975.         } else {
  976.             return Date_Calc::getWeekdayFullname($this->day, $this->month, $this->year);
  977.         }
  978.     }
  979.  
  980.     /**
  981.      * Gets the full name or abbriviated name of this month
  982.      *
  983.      * Gets the full name or abbriviated name of this month
  984.      *
  985.      * @access public
  986.      * @param boolean $abbr abbrivate the name
  987.      * @return string name of this month
  988.      */
  989.     function getMonthName($abbr = false)
  990.     {
  991.         if ($abbr) {
  992.             return Date_Calc::getMonthAbbrname($this->month);
  993.         } else {
  994.             return Date_Calc::getMonthFullname($this->month);
  995.         }
  996.     }
  997.  
  998.     /**
  999.      * Get a Date object for the day after this one
  1000.      *
  1001.      * Get a Date object for the day after this one.
  1002.      * The time of the returned Date object is the same as this time.
  1003.      *
  1004.      * @access public
  1005.      * @return object Date Date representing the next day
  1006.      */
  1007.     function getNextDay()
  1008.     {
  1009.         $day = Date_Calc::nextDay($this->day, $this->month, $this->year, "%Y-%m-%d");
  1010.         $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
  1011.         $newDate = new Date();
  1012.         $newDate->setDate($date);
  1013.         return $newDate;
  1014.     }
  1015.  
  1016.     /**
  1017.      * Get a Date object for the day before this one
  1018.      *
  1019.      * Get a Date object for the day before this one.
  1020.      * The time of the returned Date object is the same as this time.
  1021.      *
  1022.      * @access public
  1023.      * @return object Date Date representing the previous day
  1024.      */
  1025.     function getPrevDay()
  1026.     {
  1027.         $day = Date_Calc::prevDay($this->day, $this->month, $this->year, "%Y-%m-%d");
  1028.         $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
  1029.         $newDate = new Date();
  1030.         $newDate->setDate($date);
  1031.         return $newDate;
  1032.     }
  1033.  
  1034.     /**
  1035.      * Get a Date object for the weekday after this one
  1036.      *
  1037.      * Get a Date object for the weekday after this one.
  1038.      * The time of the returned Date object is the same as this time.
  1039.      *
  1040.      * @access public
  1041.      * @return object Date Date representing the next weekday
  1042.      */
  1043.     function getNextWeekday()
  1044.     {
  1045.         $day = Date_Calc::nextWeekday($this->day, $this->month, $this->year, "%Y-%m-%d");
  1046.         $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
  1047.         $newDate = new Date();
  1048.         $newDate->setDate($date);
  1049.         return $newDate;
  1050.     }
  1051.  
  1052.     /**
  1053.      * Get a Date object for the weekday before this one
  1054.      *
  1055.      * Get a Date object for the weekday before this one.
  1056.      * The time of the returned Date object is the same as this time.
  1057.      *
  1058.      * @access public
  1059.      * @return object Date Date representing the previous weekday
  1060.      */
  1061.     function getPrevWeekday()
  1062.     {
  1063.         $day = Date_Calc::prevWeekday($this->day, $this->month, $this->year, "%Y-%m-%d");
  1064.         $date = sprintf("%s %02d:%02d:%02d", $day, $this->hour, $this->minute, $this->second);
  1065.         $newDate = new Date();
  1066.         $newDate->setDate($date);
  1067.         return $newDate;
  1068.     }
  1069.  
  1070.  
  1071.     /**
  1072.      * Returns the year field of the date object
  1073.      *
  1074.      * Returns the year field of the date object
  1075.      *
  1076.      * @access public
  1077.      * @return int the year
  1078.      */
  1079.     function getYear()
  1080.     {
  1081.         return (int)$this->year;
  1082.     }
  1083.  
  1084.     /**
  1085.      * Returns the month field of the date object
  1086.      *
  1087.      * Returns the month field of the date object
  1088.      *
  1089.      * @access public
  1090.      * @return int the month
  1091.      */
  1092.     function getMonth()
  1093.     {
  1094.         return (int)$this->month;
  1095.     }
  1096.  
  1097.     /**
  1098.      * Returns the day field of the date object
  1099.      *
  1100.      * Returns the day field of the date object
  1101.      *
  1102.      * @access public
  1103.      * @return int the day
  1104.      */
  1105.     function getDay()
  1106.     {
  1107.         return (int)$this->day;
  1108.     }
  1109.  
  1110.     /**
  1111.      * Returns the hour field of the date object
  1112.      *
  1113.      * Returns the hour field of the date object
  1114.      *
  1115.      * @access public
  1116.      * @return int the hour
  1117.      */
  1118.     function getHour()
  1119.     {
  1120.         return $this->hour;
  1121.     }
  1122.  
  1123.     /**
  1124.      * Returns the minute field of the date object
  1125.      *
  1126.      * Returns the minute field of the date object
  1127.      *
  1128.      * @access public
  1129.      * @return int the minute
  1130.      */
  1131.     function getMinute()
  1132.     {
  1133.         return $this->minute;
  1134.     }
  1135.  
  1136.     /**
  1137.      * Returns the second field of the date object
  1138.      *
  1139.      * Returns the second field of the date object
  1140.      *
  1141.      * @access public
  1142.      * @return int the second
  1143.      */
  1144.     function getSecond()
  1145.     {
  1146.          return $this->second;
  1147.     }
  1148.  
  1149.     /**
  1150.      * Set the year field of the date object
  1151.      *
  1152.      * Set the year field of the date object, invalid years (not 0-9999) are set to 0.
  1153.      *
  1154.      * @access public
  1155.      * @param int $y the year
  1156.      */
  1157.     function setYear($y)
  1158.     {
  1159.         if ($y < 0 || $y > 9999) {
  1160.             $this->year = 0;
  1161.         } else {
  1162.             $this->year = $y;
  1163.         }
  1164.     }
  1165.  
  1166.     /**
  1167.      * Set the month field of the date object
  1168.      *
  1169.      * Set the month field of the date object, invalid months (not 1-12) are set to 1.
  1170.      *
  1171.      * @access public
  1172.      * @param int $m the month
  1173.      */
  1174.     function setMonth($m)
  1175.     {
  1176.         if ($m < 1 || $m > 12) {
  1177.             $this->month = 1;
  1178.         } else {
  1179.             $this->month = $m;
  1180.         }
  1181.     }
  1182.  
  1183.     /**
  1184.      * Set the day field of the date object
  1185.      *
  1186.      * Set the day field of the date object, invalid days (not 1-31) are set to 1.
  1187.      *
  1188.      * @access public
  1189.      * @param int $d the day
  1190.      */
  1191.     function setDay($d)
  1192.     {
  1193.         if ($d > 31 || $d < 1) {
  1194.             $this->day = 1;
  1195.         } else {
  1196.             $this->day = $d;
  1197.         }
  1198.     }
  1199.  
  1200.     /**
  1201.      * Set the hour field of the date object
  1202.      *
  1203.      * Set the hour field of the date object in 24-hour format.
  1204.      * Invalid hours (not 0-23) are set to 0.
  1205.      *
  1206.      * @access public
  1207.      * @param int $h the hour
  1208.      */
  1209.     function setHour($h)
  1210.     {
  1211.         if ($h > 23 || $h < 0) {
  1212.             $this->hour = 0;
  1213.         } else {
  1214.             $this->hour = $h;
  1215.         }
  1216.     }
  1217.  
  1218.     /**
  1219.      * Set the minute field of the date object
  1220.      *
  1221.      * Set the minute field of the date object, invalid minutes (not 0-59) are set to 0.
  1222.      *
  1223.      * @access public
  1224.      * @param int $m the minute
  1225.      */
  1226.     function setMinute($m)
  1227.     {
  1228.         if ($m > 59 || $m < 0) {
  1229.             $this->minute = 0;
  1230.         } else {
  1231.             $this->minute = $m;
  1232.         }
  1233.     }
  1234.  
  1235.     /**
  1236.      * Set the second field of the date object
  1237.      *
  1238.      * Set the second field of the date object, invalid seconds (not 0-59) are set to 0.
  1239.      *
  1240.      * @access public
  1241.      * @param int $s the second
  1242.      */
  1243.     function setSecond($s) {
  1244.         if ($s > 59 || $s < 0) {
  1245.             $this->second = 0;
  1246.         } else {
  1247.             $this->second = $s;
  1248.         }
  1249.     }
  1250. }
  1251.  
  1252. ?>
  1253.